package pikes.core;

import java.io.IOException;

import pikes.util.Assert;

/**
 * Generic class used as a character stream. It can be considered as a better representation of java.io.Appendable in
 * that its methods throws unchecked PrintingException. It also provides formatting options.
 * @author Peter Bona
 */
public class Printer {

	/**
	 * Default number of spaces.
	 */
	public static final int DEFAULT_NUMBER_OF_SPACES = 8;

	private boolean useTab = false;

	private int numberOfSpace = DEFAULT_NUMBER_OF_SPACES;

	private Appendable appendable = null;

	/**
	 * Constructor taking java.io.Appendable as a argument.
	 * @param appendable
	 */
	public Printer(final Appendable appendable) {
		Assert.notNull(appendable);
		this.appendable = appendable;
	}

	/**
	 * Constructor taking java.io.Appendable as a argument and boolean parameter indicating if '\t' should be used when
	 * calling tabulator().
	 * @param appendable
	 * @param useTab
	 */
	public Printer(final Appendable appendable, final boolean useTab) {
		this(appendable);
		this.useTab = useTab;
	}

	/**
	 * Constructor taking java.io.Appendable as a argument and boolean parameter indicating if '\t' should be used when
	 * calling tabulator(). If not, the third parameter is used for printing the number of ' ' characters.
	 * @param appendable
	 * @param useTab
	 */
	public Printer(final Appendable appendable, final boolean useTab, final int numberOfSpace) {
		this(appendable, useTab);
		this.numberOfSpace = numberOfSpace;
	}

	/**
	 * Prints '\n' character.
	 * @throws PrintingException
	 */
	public final void newLine() throws PrintingException {
		print('\n');
	}

	/**
	 * Prints either '\t' or ' ' character depending on the options.
	 * @throws PrintingException
	 */
	public final void tabulator() throws PrintingException {
		if (useTab) {
			print('\t');
		}
		else {
			for (int j = 0; j < numberOfSpace; j++) {
				print(' ');
			}
		}
	}

	/**
	 * Prints the character and converts java.io.IOException to PrintingException.
	 * @param c the character to print
	 * @throws PrintingException
	 */
	public final void print(final char c) throws PrintingException {
		try {
			appendable.append(c);
		}
		catch (IOException e) {
			throw new PrintingException(e);
		}
	}

	/**
	 * Prints the character sequence and converts java.io.IOException to PrintingException.
	 * @param string the character sequence
	 * @throws PrintingException
	 */
	public final void print(final CharSequence string) throws PrintingException {
		try {
			appendable.append(string);
		}
		catch (IOException e) {
			throw new PrintingException(e);
		}
	}

	/**
	 * Prints the printable. The actual printing is delegated to {@link PrinterAsAppendableAdapter}.
	 * @param printable The object to be printed.
	 * @throws PrintingException
	 */
	public final void print(final Printable printable) throws PrintingException {
		try {
			printable.print(new PrinterAsAppendableAdapter(this));
		}
		catch (IOException e) {
			throw new PrintingException(e);
		}
	}
}
